﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using IceTea.Domain.Models;
using System.Transactions;

namespace IceTea.Domain
{
    public class ProductFactory
    {
        #region Product operations
        public static int CreateNewProduct(Product product, int userId)
        {
            TransactionOptions options = new TransactionOptions()
            {
                 IsolationLevel = IsolationLevel.Serializable
            };
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, options))
            {
                using (IceTeaEntities ite = new IceTeaEntities())
                {
                    try
                    {
                        //Set new project CreatedBy and CreatedTime
                        product.CreatedBy = userId;
                        product.CreatedTime = DateTime.Now;

                        ite.Products.AddObject(product);
                        if (ite.SaveChanges() <= 0)
                            throw new DbModelException("Failed to create new product");

                        //add the created user as the admin of new project
                        ProductAdmin par = new ProductAdmin()
                        {
                            ProductId = product.Id,
                            UserId = userId
                        };
                        ite.ProductAdmins.AddObject(par);
                        if (ite.SaveChanges() <= 0)
                            throw new DbModelException("Failed to add the product admin record");

                        //create a default team for the new project
                        Team team = new Team()
                        {
                            Name = "Default Team",
                            Description = "This is the default team created automatically by system",
                            ProductId = product.Id,
                            CreatedBy = userId,
                            CreatedTime = DateTime.Now
                        };
                        ite.Teams.AddObject(team);
                        if (ite.SaveChanges() <= 0)
                            throw new DbModelException("Failed to create an new team of product");

                        scope.Complete();
                        ite.AcceptAllChanges();
                    }
                    catch (Exception e)
                    {
                        //log the error message
                        return -1;
                    }
                    
                }
            }
            
            return product.Id;
        }

        /// <summary>
        /// Get Project instance by Id
        /// </summary>
        /// <param name="projId"></param>
        /// <returns></returns>
        public static Product GetProductById(int prodId)
        {
            if (prodId > 0)
            {
                using (IceTeaEntities ite = new IceTeaEntities())
                {
                    return (from p in ite.Products where p.Id == prodId select p).SingleOrDefault();
                }
            }
            return null;
        }

        /// <summary>
        /// Get all the projects
        /// </summary>
        /// <returns></returns>
        public static IList<Product> GetAllProducts()
        {
            IList<Product> products = null;
            using (IceTeaEntities ite = new IceTeaEntities())
            {
                products = ite.Products.ToList();
            }
            return products;
        }

        public static void SwitchProduct(int productId, int userId)
        {
            Product toproject = null;

            using (IceTeaEntities ite = new IceTeaEntities())
            {
                toproject = (from p in ite.Products
                             where p.Id == productId
                             select p).SingleOrDefault();
                if (toproject == null)
                {
                    throw new DbModelException(string.Format("Product #{0} is not exist.", productId));
                }
                User user = (from u in ite.Users
                             where u.Id == userId
                             select u).SingleOrDefault();
                if (user == null)
                {
                    throw new DbModelException(string.Format("User #{0} is not exist", userId));
                }
                user.CurProdId = toproject.Id;
                user.CurTeamId = -1;
                ite.SaveChanges();
            }
        }

        public static int UpdateProductBasicInfo(Product product, int userId)
        {
            if (product == null || product.Id <= 0)
                throw new ArgumentNullException("the product instance to be updated is null or invalid");

            using (IceTeaEntities ite = new IceTeaEntities())
            {
                Product editprod = ite.Products.SingleOrDefault(p => p.Id == product.Id);
                if (editprod == null)
                    throw new ArgumentException("the product is not exist");

                editprod.CopyFrom(product);
                if (ite.SaveChanges() > 0)
                    return editprod.Id;
            }
            return -1;
        }
        #endregion

        #region Product Admin
        public static int AddProductAdmin(int productId, int userId)
        {
            using (IceTeaEntities ite = new IceTeaEntities())
            {
                //Verify the user is not the admin of the specified project
                if ((from pa in ite.ProductAdmins
                     where pa.ProductId == productId && pa.UserId == userId
                     select pa.Id).Count() > 0)
                    return -1;

                //create one new projectadmin record in Db
                ProductAdmin par = new ProductAdmin()
                {
                    ProductId = productId,
                    UserId = userId
                };
                ite.ProductAdmins.AddObject(par);
                if (ite.SaveChanges() <= 0)
                    throw new DbModelException("Failed to add the project admin record");

                return par.Id;
            }
        }
        #endregion

        #region Product Release
        public static int AddNewRelease(Release release, int userId)
        {
            using (IceTeaEntities ite = new IceTeaEntities())
            {
                release.CreatedBy = userId;
                release.CreatedTime = DateTime.Now;
                release.UpdatedBy = userId;
                release.UpdatedTime = DateTime.Now;

                ite.Releases.AddObject(release);
                if (ite.SaveChanges() > 0)
                    return release.Id;
            }
            return -1;
        }

        public static int UpdateRelease(Release release, int userId)
        {
            using (IceTeaEntities ite = new IceTeaEntities())
            {
                Release editRelease = ite.Releases.SingleOrDefault(r => r.Id == release.Id);

                if (editRelease != null)
                {
                    editRelease.CopyFrom(release);
                    editRelease.UpdatedBy = userId;
                    editRelease.UpdatedTime = DateTime.Now;

                    if (ite.SaveChanges() > 0)
                        return release.Id;
                }
                                
            }
            return -1;
        }

        public static IList<Release> GetAllReleases(int prodId)
        {
            using (IceTeaEntities ite = new IceTeaEntities())
            {
                return ite.Releases.Where(r => r.ProductId == prodId).ToList();
            }
        }

        public static Release GetRelease(int releaseId)
        {
            using (IceTeaEntities ite = new IceTeaEntities())
            {
                return ite.Releases.Where(r => r.Id == releaseId).SingleOrDefault();
            }
        }
        #endregion

        #region Product Teams
        public static IEnumerable<Team> GetProductTeams(int prodId)
        {
            IEnumerable<Team> results = new List<Team>();

            if (prodId > 0)
            {
                using (IceTeaEntities ite = new IceTeaEntities())
                {
                    results = (from t in ite.Teams
                               where t.ProductId == prodId
                               select t).ToList();

                }
            }
            return results;
        }
        #endregion
    }
}
